home *** CD-ROM | disk | FTP | other *** search
/ PC Professionell 2006 June / PCpro_2006_06.ISO / files / freeware / openvip.exe / {app} / model.py < prev    next >
Encoding:
Python Source  |  2003-06-04  |  13.0 KB  |  352 lines

  1. #
  2. # This file is part of OpenVIP (http://openvip.sourceforge.net)
  3. #
  4. # Copyright (C) 2002-2003
  5. # Michal Dvorak, Jiri Sedlar, Antonin Slavik, Vaclav Slavik, Jozef Smizansky
  6. #
  7. # This program is licensed under GNU General Public License version 2;
  8. # see file COPYING in the top level directory for details.
  9. #
  10. # $Id: model.py,v 1.29 2003/06/04 12:26:20 xjozo Exp $
  11. #
  12. # Timeline data model for the editor. Class Timeline holds all information
  13. # about edited timeline file and 1-1 corresponds to XML file in OpenVIP's
  14. # "Timeline Format".
  15. #
  16.  
  17.  
  18.  
  19. class Error(Exception):
  20.     """Exception raised when loading/saving/converting model fails.
  21.        self.msg contains error description."""
  22.     def __init__(self, msg):
  23.         self.msg = msg
  24.     def __str__(self):
  25.         return self.msg
  26.  
  27. # -------------------------------------------------------------------------
  28. #                            Timeline objects:
  29. # -------------------------------------------------------------------------
  30.  
  31. # NB: Note that most classes have attributes described only in their docstring,
  32. #     but not initialized in constructor. This is on purpose: like this,
  33. #     Python will raise AttributeError when accessing attributes that are not
  34. #     properly filled in.
  35.  
  36. class Filter:
  37.     """
  38.     Filter (see openvip::VideoFilter, openvip::AudioFilter) applied to Object.
  39.     
  40.     Attributes:
  41.         name      - name of the filter plugin to apply
  42.         params    - parameters for the filter plugin. It is a dictionary with
  43.                     string keys and string values and corresponds to parameters
  44.                     accepted by the plugin implementation.
  45.                     Assign values like this:
  46.                         f.params["width"] = "320"
  47.                         f.params["height"] = "240"
  48.         active    - a boolean value to quickly turn on/off this filter
  49.                     (corresponds to state of CheckListBox in ObjectPanel) 
  50.     """
  51.     def __init__(self):
  52.         self.name = None
  53.         self.params = {}
  54.         self.active = True
  55.  
  56.  
  57. class Group:
  58.     """
  59.     Group object represents group of binded Objects and/or
  60.     Transitions. Objects in group move together when any member of the
  61.     group is moved on the timeline in the editor.
  62.  
  63.     Attributes:
  64.         objects   - list of Object or Transition references
  65.         id        - string with unique ID of the group
  66.     """
  67.     def __init__(self):
  68.         self.objects = []
  69.  
  70.  
  71. class SomethingOnTimeline:
  72.     def length(self):
  73.         """Returns length of the object in seconds."""
  74.         return self.time_to - self.time_from
  75.  
  76.     def move(self, pos):
  77.         """Moves the object to new position (in seconds)."""
  78.         len = self.length()
  79.         self.time_from = pos
  80.         self.time_to = pos + len
  81.  
  82.     def isAudio(self):
  83.         return self.track[0] == 'A'
  84.     def isVideo(self):
  85.         return self.track[0] == 'V'
  86.  
  87.  
  88. class Object(SomethingOnTimeline):
  89.     """
  90.     Object is single video/audio clip pasted on the timeline.
  91.  
  92.     Attributes:
  93.         id        - string with unique ID of the object
  94.         time_from - position of the object on the timeline, in seconds
  95.                     since beginning
  96.         time_to   - position of end of the object on the timeline
  97.                     (time_to-time_from gives object's length in seconds)
  98.         track     - string identifying the track that this object is placed on.
  99.                     Valid values match regex [AV]([AB]|[0-9]+)
  100.         src_spec  - specification of the source. This is dictionary with
  101.                     string keys and string values and corresponds to parameters
  102.                     accepted by corresponding input plugin.
  103.                     Note: There MUST be "filename" key in the dictionary!                           Example: myobj.src_spec["filename"] = "foo.avi"
  104.  
  105.         src_from - position of the object in the source file, in seconds
  106.                     since beginning
  107.         src_to   - position of end of the object in the source file
  108.                    src_to = 0 means end of the source 
  109.         src_channel
  110.                   - string identification of input track to use. Corresponds
  111.                     to output connectors in terminology of OpenVIP core and
  112.                     is usually 'video0' or 'audio0'.
  113.         filters   - list of Filter object references
  114.     """
  115.     def __init__(self):
  116.         self.src_spec = {}
  117.         self.filters = []
  118.  
  119.  
  120. class Transition(SomethingOnTimeline):
  121.     """
  122.     Transition object represents transition between two audio or video track
  123.     (you wouldn't guess).
  124.  
  125.     Attributes:
  126.         id        - string with unique ID of the transition
  127.         time_from - position of the object on the timeline, in seconds
  128.                     since beginning
  129.         time_to   - position of end of the object on the timeline
  130.                     (time_to-time_from gives object's length in seconds)
  131.         track     - track to apply the transition to. Either 'VFx' or 'AFx'
  132.         direction - direction of the effect, either 'AB' or 'BA'
  133.         name      - name of the transition plugin to apply
  134.         params    - parameters for the transition plugin, see Filter.params
  135.                     for more information
  136.     """
  137.     def __init__(self):
  138.         self.params = {}
  139.  
  140.  
  141. class Timeline:
  142.     """
  143.     Representation of all data contained in edited timeline.
  144.  
  145.     Attributes:
  146.         objects     - list of Object references
  147.         transitions - list of Transition references
  148.         groups      - list of Group references
  149.     """
  150.     def __init__(self):
  151.         self.objects = []
  152.         self.transitions = []
  153.         self.groups = []
  154.  
  155.     def toxml(self):
  156.         """Converts the object into XML representation."""
  157.         import xml.dom.minidom, conv
  158.         dom = conv.data_to_dom(self,
  159.                     "http://openvip.sourceforge.net/timeline-format","1.0")
  160.         s = dom.toxml()
  161.         dom.unlink()
  162.         return s
  163.     
  164.     def tonetworkxml(self, filename, videoFormat, audioFormat,
  165.                      time_from=None, time_to=None, previewQuality=False,
  166.                      out_params={}):
  167.         """Converts the object into XML network format representation.
  168.            time_from, time_to    - convert only part of the timeline
  169.            filename              - name of output file created by the network.
  170.                                    May be None to produce network that renders
  171.                                    into memory buffer
  172.            output_params         - dictionary with additional
  173.         """
  174.         import xml.dom.minidom, conv2
  175.         if time_from == None:
  176.             time_from = self.beginning()
  177.         if time_to == None:
  178.             time_to = self.length()
  179.         if previewQuality:
  180.             quality = "preview"
  181.         else:
  182.             quality = "final"
  183.         out_params['filename']=filename
  184.         return conv2.data_to_network(data=self,
  185.                               xmlns="http://openvip.sourceforge.net/network-format",
  186.                               version="1.0",
  187.                               def_video=videoFormat, def_audio=audioFormat,
  188.                               quality=quality,
  189.                               output_params=out_params,
  190.                               tmln_length=time_to-time_from, tmln_start=time_from)
  191.     
  192.     def save(self, filename):
  193.         """Saves the object to file."""
  194.         f = open(filename, 'wt')
  195.         f.write(self.toxml())
  196.         f.close()
  197.         import xmlhelpers
  198.         xmlhelpers.formatNicely(filename)
  199.  
  200.     def length(self):
  201.         """Returns length of the timeline in seconds -- that is, the distance
  202.            between time 0 and right part of the right-most object."""
  203.         w = 0
  204.         for o in self.objects:
  205.             if o.time_to > w: w = o.time_to
  206.         return w
  207.     
  208.     def beginning(self):
  209.         """Returns time of beginning of the timeline in seconds."""
  210.         if len(self.objects) == 0: return 0
  211.         w = self.objects[0].time_from
  212.         for o in self.objects:
  213.             if o.time_from < w: w = o.time_from
  214.         return w
  215.     
  216.     def cut(self,time,selection = []):
  217.         """Cuts entire Timline in time position, i.e. each object which
  218.            includes time position is cuted and each involved group is devided
  219.            and its objects are redistributed between two devoloped groups."""
  220.         import copy
  221.         groups_to_add = []
  222.         objects_to_remove = []
  223.         for gr in self.groups:
  224.             if toCut(gr,time):
  225.                 add_gr = Group()
  226.                 add_gr.id = getUniqueID(self,"group",groups_to_add)
  227.                 for o in gr.objects:
  228.                     if selection != [] and o not in selection:continue
  229.                     if toCut(o,time):
  230.                         addobj = copy.deepcopy(o)
  231.                         addobj.time_to = time
  232.                         o.time_from = time
  233.                         
  234.                         if isinstance(o,Object):
  235.                             addobj.src_to = addobj.src_from + (time - addobj.time_from)
  236.                             o.src_from = addobj.src_from + (time - addobj.time_from)
  237.                             addobj.id = getUniqueID(self,"object")
  238.                         if isinstance(o,Transition):addobj.id = getUniqueID(self,"trans")
  239.                         add_gr.objects.append(addobj)
  240.                         if isinstance(o,Object):self.objects.append(addobj)
  241.                         if isinstance(o,Transition):self.transitions.append(addobj)
  242.                     else:
  243.                         if o.time_to <= time:
  244.                             add_gr.objects.append(o)
  245.                             objects_to_remove.append(o)
  246.                 for ro in objects_to_remove:gr.objects.remove(ro)
  247.                 if len(add_gr.objects) > 0:groups_to_add.append(add_gr)
  248.         self.groups.extend(groups_to_add)
  249.         
  250.         obj_to_add = []
  251.         for o in self.objects:
  252.             if selection != [] and o not in selection:continue
  253.             if toCut(o,time):
  254.                 addobj = copy.deepcopy(o)
  255.                 addobj.time_to = time
  256.                 addobj.src_to = addobj.src_from + (time - addobj.time_from)
  257.                 o.time_from = time
  258.                 o.src_from = addobj.src_from + (time - addobj.time_from)
  259.                 addobj.id = getUniqueID(self,"object",obj_to_add)
  260.                 obj_to_add.append(addobj)
  261.         self.objects.extend(obj_to_add)
  262.         
  263.         trans_to_add = []
  264.         for o in self.transitions:
  265.             if selection != [] and o not in selection:continue
  266.             if toCut(o,time):
  267.                 addobj = copy.deepcopy(o)
  268.                 addobj.time_to = time
  269.                 o.time_from = time
  270.                 addobj.id = getUniqueID(self,"trans",trans_to_add)
  271.                 trans_to_add.append(addobj)              
  272.         self.transitions.extend(trans_to_add)   
  273.                         
  274.                     
  275. def getUniqueID(t,root,added = []):
  276.     i=0
  277.     while(1):
  278.         id = "%s%d"%(root,i)
  279.         if inTmln(id,t,added)==0:break
  280.         i+=1
  281.     return id
  282.         
  283. def inTmln(id,t,added):
  284.     for o  in t.objects:
  285.         if o.id == id:return 1
  286.     for tr in t.transitions:
  287.         if tr.id == id:return 1
  288.     for gr in t.groups:
  289.         if gr.id == id:return 1
  290.     for o in added:
  291.         if o.id == id:return 1
  292.     return 0
  293.         
  294.         
  295.  
  296. def toCut(o,time):
  297.     if isinstance(o,Group):
  298.        for obj in o.objects:
  299.             if obj.time_from < time and obj.time_to > time:
  300.                 return 1
  301.     if isinstance(o,Object) or isinstance(o,Transition):
  302.         if o.time_from < time and o.time_to > time:
  303.             return 1
  304.     
  305.     return 0
  306.                     
  307.  
  308. def load(filename):
  309.     """Loads Timeline object from XML file.
  310.        Raises model.Error in case of failure."""
  311.     import xml.dom.minidom, conv, xmlhelpers
  312.     if not xmlhelpers.validate(filename):
  313.         raise Error("File '%s' doesn't conform to DTD." % filename)
  314.     dom = xml.dom.minidom.parse(filename)
  315.     data = conv.dom_to_data(dom)
  316.     dom.unlink()
  317.     return data
  318.  
  319.  
  320.  
  321. # -------------------------------------------------------------------------
  322. #        Classes for storing information about output stream format:
  323. # -------------------------------------------------------------------------
  324.  
  325. class VideoFormat:
  326.         """Description of output format for video track."""
  327.         def __init__(self,i):
  328.                 "i is VideoStreamInfo object"
  329.                 self.width = i.width
  330.                 self.height = i.height
  331.                 self.fps = i.fps
  332.                 self.aspect_ratio = i.aspect_ratio
  333.         def __init__(self,width,height,fps,aspect_ratio=None):
  334.                 self.width = width
  335.                 self.height = height
  336.                 self.fps = fps
  337.                 if aspect_ratio == None:
  338.                     self.aspect_ratio = float(width)/float(height)
  339.                 else:
  340.                     self.aspect_ratio = aspect_ratio
  341.  
  342. class AudioFormat:
  343.         """Description of output format for audio track."""
  344.         def __init__(self,i):
  345.                 "i is AudioStreamInfo object"
  346.                 self.sample_rate = i.sample_rate
  347.                 self.channels = i.channels
  348.         def __init__(self,sample_rate,channels):
  349.                 self.sample_rate = sample_rate
  350.                 self.channels = channels
  351.  
  352.